Cron 是基於時間的工作排程系統,而 WP-Cron 是 WordPress 中處理工作的基於時間的工作排程系。WordPress 的有很多的核心功能,例如說:檢查更新、排程發布文章這類的功能,都是使用了 WP-Cron。
WP-Cron 的工作原理是,在頁面被讀取的時候,才會開始檢查工作排程列表以查看需要運行的工作。 也因此 WP-Cron 和 Unix 系統的 Cron 運行方式是不一樣的。舉例:如果我們安排了一個工作在早上 10:00 運行,而在這之前都沒有發生任何頁面加載,則該排程也就都不會運行。
那為什麼我們要使用 WP-Cron 呢?
因為,很多虛擬主機不允許用戶訪問系統 Cron,但 WordPress 核心和許多外掛還是得需要一個 Cron 系統來執行一些排程工作呀!因此 WordPress 提供了這種通過頁面載入後去觸發 WP-Cron 系統的機制。
雖然這種運作方式,不一定會在特定的時間『準時』運行,但是 WP-Cron 也有一定的機率去完成我們的排程工作,所以還算是可以用。
想較於系統 Cron ,WP-Cron 系統也是有好處的,今天如果是 Unix 系統的工作排程,假設說沒有在特定的時間執行,他就永遠真的不會執行了。而 WP-Cron ,工作將一直在佇列中,直到有一個頁面加載時觸發他們。也就是說每一次頁面載入的時候,會去檢查並且執行過期而沒有運行的工作(不管這個工作過期過久),因此,通過 WP-Cron 設置的排程工作不會沒執行到。
Unix 系統的 Cron 是會在特定的時間去運行,而 WP-Cron 則是使用時間間隔來模擬系統 Cron。
什麼意思?首先給第一個工作一個運行時間,然後設置一個時間間隔,以秒為單位,之後按照時間間隔重複工作。例如,我們安排了一個 早上 10:00
開始,間隔 300 秒
的排程工作。
會發生什麼事情?該工作首先會在這個 早上 10:00
被運行一次,然後在 早上 10:05
再被運行一次,然後每隔 300 秒就會被再運行一次。
WordPress 提供了 cron_schedules hook 讓我們可以創建一個過濾器來添加自定義時間間隔,如下:
add_filter( 'cron_schedules', 'example_add_cron_interval' );
function example_add_cron_interval( $schedules ) {
$schedules[ 'every-5-minutes' ] = array(
'interval' => 5 * MINUTE_IN_SECONDS,
'display' => __( 'Every 5 minutes', 'devhub' ) );
return $schedules;
}
我們就創建了一個新的時間間隔,允許我們每 5 分鐘運行一次 Cron 工作。
為了讓我們的工作執行,我們需要創建一個自定義 hook,並掛載一個 callback function 到這個 hook 上,這是非常重要的一步,忘了這一步,我們的工作永遠不會被執行。
add_action( 'bl_cron_hook', 'bl_cron_exec' );
現在,我們來進行實際的工作排程。另外, WordPress 提供了一個 wp_next_scheduled() 函式來幫助我們檢查一個特定的工作是否已經被排程。
wp_next_scheduled() 函式很簡單,只接收一個參數 hook 的名稱
,使用的時候如果有抓到工作排程,就會回傳一個包含下一個執行時間的字串,否則就會回傳 false ,使用方法如下:
wp_next_scheduled( 'bl_cron_hook' );
我們使用 wp_schedule_event() 來完成重複工作的呼叫,該函式需要三個必需的參數,參數如下:
我們將使用 5 秒的時間間隔和我們之前創建的 hook 來演示一下:
wp_schedule_event( time(), 'five_seconds', 'bl_cron_hook' );
記住,我們需要首先確保該工作排程尚未被安排,程式碼如下:
if ( ! wp_next_scheduled( 'bl_cron_hook' ) ) {
wp_schedule_event( time(), 'five_seconds', 'bl_cron_hook' );
}
當我們不再需要某個排程工作時,我們也可以取消,我們使用 wp_unschedule_event() 函式來取消工作排程,該函式有兩個參數:
這個函式不僅可以取消在每個 timestamp 執行的排程工作,還可以取消未來所有的工作排程。
如果不知道下一個工作的 timestamp,我們可以使用 wp_next_scheduled() 函式來查找,該函式需要一個參數:
把上面的程式碼組合在一起使用,看起來應該像下面這樣:
$timestamp = wp_next_scheduled( 'bl_cron_hook' );
wp_unschedule_event( $timestamp, 'bl_cron_hook' );
當我們不再需要某些工作排程的時候,取消這些工作排程非常重要,不然 WordPress 會繼續嘗試執行他們。
取消排程工作的重要時機就是禁用外掛的時候,很多外掛都忘記了這一點,忘記清理不再需要的工作排程。 而 WordPress 也為我們提供了一個名為 register_deactivation_hook() 函式,允許開發人員在外掛停用的時候使用,詳細可以參考我第六天分享的內容:WordPress 啟用、停用、刪除外掛
程式碼如下:
PHP
register_deactivation_hook( __FILE__, 'bl_deactivate' );
function bl_deactivate() {
$timestamp = wp_next_scheduled( 'bl_cron_hook' );
wp_unschedule_event( $timestamp, 'bl_cron_hook' );
}
如我們上面介紹的,WP-Cron 的執行依賴於頁面加載,不一定會嚴格『準時』執行。但是如果我們真的有那種必需『準時』執行的工作,這會是一個問題。
還好,我們有一個簡單的解決辦法來避免這個問題。我們只需將系統的工作排程設置為按我們所需的時間間隔執行即可。什麼意思?
就是我們直接使用工具向 wp-cron.php 文件發送請求。
在這之前,因為我們會直接在系統上安排工作排程,也就不需要 WordPress 在每個頁面載入的時候,幫我們執行工作排程,所以我們可以先禁用掉這個功能,來節約這個不必要的伺服器負擔。
我們可以在 wp-config.php 中設定開關,在 wp-config.php 中加上以下程式碼即可。
define('DISABLE_WP_CRON', true);
因為我手邊沒有 Windows ,所以這邊我就只有介紹 Mac OS X 和 Linux 。用 Windows 的朋友可能要另外爬文了。Mac OS X 和 Linux 的部分都是使用 Cron 作為基於時間的排程系統,可以直接從 terminal 設定。
crontab -e
Cron 有一個特定的語法。
設置工作排程的時候,如果不考慮的時間段,我們會使用 *
號代替。例如,如果我們需要每隔 15 分鐘運行一次命令,而不考慮小時、日期和月份,排程工作設置如下:
15 * * * * command
許多伺服器都自帶了 wget
工具,我們可以直接使用這個工具來訪問 WordPress 的 Cron 文件。
wget http://YOUR_SITE_URL/wp-cron.php
搭配上剛剛學到的 corn ,假設我們每天凌晨觸發網站的 WordPress Cron ,最後的 Cron 設置會變成這樣:
0 0 * * * wget http://YOUR_SITE_URL/wp-cron.php